#include <linux/init.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define FIRSTMINOR 0
#define DEV_COUNT 1

static dev_t dev;
static struct cdev *complete_cdev;
struct completion comp;

DECLARE_COMPLETION(comp);

ssize_t complete_read(struct file * filp, char __user * buf, 
				size_t count, loff_t * ops)
{
	printk(KERN_DEBUG "process %i (%s) going to sleep\n",
			current->pid, current->comm);
	wait_for_completion(&comp);
	printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
	return 0;
	
}

ssize_t complete_write(struct file * filp, const char __user * buf, 
				size_t count, loff_t * ops)
{
	printk(KERN_DEBUG "process %i (%s) awakening the readers ... \n", 
				current->pid, current->comm);
	complete(&comp);
	return count;
}

struct file_operations complete_fops = {
	.owner = THIS_MODULE,
	.read = complete_read,
	.write = complete_write,
};

static void complete_exit(void)
{
	cdev_del(complete_cdev);
	unregister_chrdev_region(dev, DEV_COUNT);
}


static int complete_init(void)
{
	int result;
	result = alloc_chrdev_region(&dev, FIRSTMINOR, DEV_COUNT, "complete");
	if (result < 0)
		return result;

	complete_cdev = cdev_alloc();
	complete_cdev->ops = &complete_fops;

	cdev_init(complete_cdev, &complete_fops);
	complete_cdev->owner = THIS_MODULE;
	result = cdev_add(complete_cdev, dev, DEV_COUNT);
	if (result < 0) {
		complete_exit();
		return result;
	}

	return 0;
	
}

module_init(complete_init);
module_exit(complete_exit);

MODULE_LICENSE("Dual BSD/GPL");



